const fs = require('fs');
const path = require('path');
const chokidar = require('chokidar');
const { getDb, runQuery, getQuery, withTransaction } = require('../models/database');

// 全局状态
let scanInterval = null;
let isScanning = false;

/**
 * 初始化扫描服务
 * @param {string} dirPath 小说目录路径
 * @param {number} intervalSeconds 扫描间隔（秒）
 */
function initializeScanService(dirPath, intervalSeconds = 3600) {
  console.log(`[scanner] 初始化扫描服务: 目录=${dirPath}, 间隔=${intervalSeconds}秒`);
  
  // 确保目录存在
  if (!fs.existsSync(dirPath)) {
    console.log(`[scanner] 创建小说目录: ${dirPath}`);
    fs.mkdirSync(dirPath, { recursive: true });
  }
  
  // 清除之前的扫描定时器
  if (scanInterval) {
    clearInterval(scanInterval);
  }
  
  // 启动后立即进行一次扫描
  console.log(`[scanner] 首次扫描即将启动...`);
  setTimeout(() => {
    scanDirectory(dirPath)
      .then(count => {
        console.log(`[scanner] 首次扫描完成，发现 ${count} 本小说`);
      })
      .catch(err => {
        console.error(`[scanner] 首次扫描失败:`, err);
      });
  }, 1000); // 延迟1秒，确保数据库已初始化
  
  // 设置定期扫描
  scanInterval = setInterval(() => {
    console.log(`[scanner] 定期扫描启动 - ${new Date().toISOString()}`);
    scanDirectory(dirPath)
      .then(count => {
        console.log(`[scanner] 定期扫描完成，发现 ${count} 本小说`);
      })
      .catch(err => {
        console.error(`[scanner] 定期扫描失败:`, err);
      });
  }, intervalSeconds * 1000);
  
  console.log(`[scanner] 扫描服务初始化完成，间隔设置为 ${intervalSeconds} 秒`);
}

/**
 * 设置文件监控
 * @param {string} dirPath 要监控的目录路径
 */
function setupFileWatcher(dirPath) {
  const watcher = chokidar.watch(dirPath, {
    ignored: /(^|[\/\\])\../, // 忽略隐藏文件
    persistent: true,
    ignoreInitial: true
  });
  
  watcher
    .on('add', filePath => {
      if (filePath.endsWith('.txt')) {
        console.log(`检测到新文件: ${filePath}`);
        processFile(filePath);
      }
    })
    .on('change', filePath => {
      if (filePath.endsWith('.txt')) {
        console.log(`检测到文件变更: ${filePath}`);
        processFile(filePath);
      }
    })
    .on('unlink', filePath => {
      if (filePath.endsWith('.txt')) {
        console.log(`检测到文件删除: ${filePath}`);
        removeFile(filePath);
      }
    });
    
  console.log(`文件监控已启动 - 目录: ${dirPath}`);
}

/**
 * 扫描目录下的所有小说文件
 * @param {string} dirPath 小说目录路径
 * @returns {Promise<number>} 小说数量
 */
async function scanDirectory(dirPath) {
  // 防止多次扫描同时进行
  if (isScanning) {
    console.log(`[scanner] 已有扫描正在进行，跳过此次扫描`);
    return 0;
  }
  
  isScanning = true;
  console.log(`[scanner] 开始扫描目录: ${dirPath}`);
  const startTime = Date.now();
  
  try {
    // 确保目录存在
    if (!fs.existsSync(dirPath)) {
      console.warn(`[scanner] 目录不存在: ${dirPath}，将创建`);
      fs.mkdirSync(dirPath, { recursive: true });
    }
    
    // 读取目录下的所有txt文件
    const files = await findAllTxtFiles(dirPath);
    console.log(`[scanner] 在目录中找到 ${files.length} 个txt文件`);
    
    // 过滤得到新增的文件
    const existingFiles = await getExistingFiles();
    const existingPathsMap = new Map(existingFiles.map(file => [file.path, file]));
    
    // 区分新增、更新和删除的文件
    const newFiles = [];
    const updatedFiles = [];
    const allCurrentFiles = new Set(); // 当前存在的所有文件路径
    
    for (const file of files) {
      allCurrentFiles.add(file.path);
      
      if (!existingPathsMap.has(file.path)) {
        // 新增文件
        newFiles.push(file);
      } else {
        // 已存在的文件，检查是否需要更新
        const existingFile = existingPathsMap.get(file.path);
        if (file.size !== existingFile.size || file.modified !== existingFile.modified) {
          updatedFiles.push({
            ...file,
            id: existingFile.id
          });
        }
      }
    }
    
    // 检测已删除的文件
    const deletedFiles = [];
    for (const existingFile of existingFiles) {
      if (!allCurrentFiles.has(existingFile.path)) {
        deletedFiles.push(existingFile);
      }
    }
    
    console.log(`[scanner] 文件分析结果: 新增=${newFiles.length}, 更新=${updatedFiles.length}, 删除=${deletedFiles.length}`);
    
    // 更新数据库
    let addedCount = 0;
    let updatedCount = 0;
    let deletedCount = 0;
    
    // 添加新文件
    if (newFiles.length > 0) {
      console.log(`[scanner] 开始添加新文件: ${newFiles.length} 个`);
      for (const file of newFiles) {
        try {
          await addNovel(file);
          addedCount++;
          
          if (addedCount % 10 === 0) {
            console.log(`[scanner] 已添加 ${addedCount}/${newFiles.length} 个新文件`);
          }
        } catch (err) {
          console.error(`[scanner] 添加文件失败: ${file.path}`, err);
        }
      }
    }
    
    // 更新修改的文件
    if (updatedFiles.length > 0) {
      console.log(`[scanner] 开始更新文件: ${updatedFiles.length} 个`);
      for (const file of updatedFiles) {
        try {
          await updateNovel(file);
          updatedCount++;
          
          if (updatedCount % 10 === 0) {
            console.log(`[scanner] 已更新 ${updatedCount}/${updatedFiles.length} 个文件`);
          }
        } catch (err) {
          console.error(`[scanner] 更新文件失败: ${file.path}`, err);
        }
      }
    }
    
    // 删除不存在的文件
    if (deletedFiles.length > 0) {
      console.log(`[scanner] 开始删除文件: ${deletedFiles.length} 个`);
      for (const file of deletedFiles) {
        try {
          await deleteNovel(file.id);
          deletedCount++;
          
          if (deletedCount % 10 === 0) {
            console.log(`[scanner] 已删除 ${deletedCount}/${deletedFiles.length} 个文件`);
          }
        } catch (err) {
          console.error(`[scanner] 删除文件失败: ${file.path}`, err);
        }
      }
    }
    
    const duration = Math.round((Date.now() - startTime) / 1000);
    console.log(`[scanner] 扫描完成 - 耗时: ${duration}秒, 新增: ${addedCount}, 更新: ${updatedCount}, 删除: ${deletedCount}`);
    
    return files.length;
  } catch (err) {
    console.error(`[scanner] 扫描过程中出错:`, err);
    throw err;
  } finally {
    isScanning = false;
  }
}

/**
 * 获取已存在的文件列表
 * @returns {Promise<Array>} 已存在的文件列表
 */
async function getExistingFiles() {
  console.log(`[scanner] 获取数据库中已存在的文件列表`);
  const db = getDb();
  
  try {
    const sql = 'SELECT id, path, size, modified FROM novels';
    const rows = await new Promise((resolve, reject) => {
      db.all(sql, [], (err, rows) => {
        if (err) {
          console.error(`[scanner] 读取现有文件失败:`, err);
          reject(err);
          return;
        }
        resolve(rows || []);
      });
    });
    
    console.log(`[scanner] 从数据库获取到 ${rows.length} 个文件记录`);
    return rows;
  } catch (err) {
    console.error(`[scanner] 获取现有文件失败:`, err);
    return [];
  }
}

/**
 * 递归查找目录下的所有txt文件
 * @param {string} dir 目录路径
 * @returns {Promise<Array>} 文件路径列表
 */
async function findAllTxtFiles(dir) {
  console.log(`[scanner] 开始在目录中搜索txt文件: ${dir}`);
  const txtFiles = [];
  
  async function scanDir(currentDir, depth = 0) {
    if (depth > 10) {
      console.warn(`[scanner] 目录嵌套超过10层，忽略后续扫描: ${currentDir}`);
      return;
    }
    
    try {
      const entries = fs.readdirSync(currentDir, { withFileTypes: true });
      
      for (const entry of entries) {
        const fullPath = path.join(currentDir, entry.name);
        
        if (entry.isDirectory()) {
          await scanDir(fullPath, depth + 1);
        } else if (entry.isFile() && entry.name.toLowerCase().endsWith('.txt')) {
          // 获取文件信息
          const stats = fs.statSync(fullPath);
          txtFiles.push({
            name: path.basename(entry.name, '.txt'), // 去掉.txt后缀
            path: fullPath,
            size: stats.size,
            modified: stats.mtime.toISOString()
          });
        }
      }
    } catch (err) {
      console.error(`[scanner] 读取目录失败: ${currentDir}`, err);
    }
  }
  
  await scanDir(dir);
  console.log(`[scanner] 文件搜索完成，找到 ${txtFiles.length} 个txt文件`);
  return txtFiles;
}

/**
 * 添加小说到数据库
 * @param {Object} novel 小说信息
 * @returns {Promise<Object>} 数据库操作结果
 */
async function addNovel(novel) {
  console.log(`[scanner] 添加新小说: "${novel.name}", 路径: ${novel.path}`);
  
  const sql = `
    INSERT INTO novels (name, path, size, modified, added)
    VALUES (?, ?, ?, ?, ?)
  `;
  
  const params = [
    novel.name,
    novel.path,
    novel.size,
    novel.modified,
    new Date().toISOString()
  ];
  
  try {
    const result = await runQuery(sql, params);
    console.log(`[scanner] 小说添加成功: "${novel.name}", ID: ${result.lastID}`);
    return result;
  } catch (err) {
    console.error(`[scanner] 添加小说失败: "${novel.name}"`, err);
    throw err;
  }
}

/**
 * 更新小说信息
 * @param {Object} novel 小说信息
 * @returns {Promise<Object>} 数据库操作结果
 */
async function updateNovel(novel) {
  console.log(`[scanner] 更新小说: "${novel.name}" (ID: ${novel.id}), 路径: ${novel.path}`);
  
  const sql = `
    UPDATE novels
    SET size = ?, modified = ?
    WHERE id = ?
  `;
  
  const params = [
    novel.size,
    novel.modified,
    novel.id
  ];
  
  try {
    const result = await runQuery(sql, params);
    console.log(`[scanner] 小说更新成功: "${novel.name}" (ID: ${novel.id}), 影响记录数: ${result.changes}`);
    return result;
  } catch (err) {
    console.error(`[scanner] 更新小说失败: "${novel.name}" (ID: ${novel.id})`, err);
    throw err;
  }
}

/**
 * 删除小说记录
 * @param {number} id 小说ID
 * @returns {Promise<Object>} 数据库操作结果
 */
async function deleteNovel(id) {
  console.log(`[scanner] 删除小说: ID=${id}`);
  
  // 首先获取小说信息，用于日志记录
  let novelName = null;
  try {
    const novel = await getQuery('SELECT name FROM novels WHERE id = ?', [id]);
    if (novel) {
      novelName = novel.name;
    }
  } catch (err) {
    console.warn(`[scanner] 获取被删除小说信息失败: ID=${id}`, err);
  }
  
  const sql = 'DELETE FROM novels WHERE id = ?';
  
  try {
    const result = await runQuery(sql, [id]);
    if (novelName) {
      console.log(`[scanner] 小说删除成功: "${novelName}" (ID: ${id}), 影响记录数: ${result.changes}`);
    } else {
      console.log(`[scanner] 小说删除成功: ID=${id}, 影响记录数: ${result.changes}`);
    }
    return result;
  } catch (err) {
    console.error(`[scanner] 删除小说失败: ID=${id}`, err);
    throw err;
  }
}

/**
 * 清理扫描服务
 */
function cleanupScanService() {
  console.log(`[scanner] 清理扫描服务`);
  
  if (scanInterval) {
    clearInterval(scanInterval);
    scanInterval = null;
    console.log(`[scanner] 扫描定时器已清理`);
  } else {
    console.log(`[scanner] 没有活动的扫描定时器`);
  }
}

/**
 * 手动触发扫描
 * @param {string} dirPath 要扫描的目录路径
 * @returns {Promise<number>} 扫描的文件数量
 */
function triggerScan(dirPath) {
  console.log(`[scanner] 手动触发扫描: ${dirPath}`);
  return scanDirectory(dirPath);
}

module.exports = {
  initializeScanService,
  triggerScan,
  scanDirectory,
  cleanupScanService
}; 